﻿using Microsoft.WindowsAPICodePack.Shell;
using StableDiffusionTools.Framework;
using StableDiffusionTools.Imaging;
using StableDiffusionTools.Utils;
using System;
using System.Collections.Concurrent;
using System.Drawing;
using System.Threading;
using TaggingToolkit.Events;

namespace TaggingToolkit.Framework
{
    public class ThreadedThumbnailLoader
    {
        public event EventHandler<LoadedThumbnailEventArgs> LoadedThumbnail;
        protected void OnLoadedThumbnail(DataTags tags, Bitmap img)
        {
            if (LoadedThumbnail == null)
                return;

            context.Post(delegate { LoadedThumbnail.Invoke(this, new LoadedThumbnailEventArgs(tags, img)); }, null);
        }

        object locker = new object();
        SynchronizationContext context;
        ConcurrentQueue<ThumbnailWorkItem> queue;
        ConcurrentDictionary<DataTags, ThumbnailWorkItem> schedule;
        volatile bool shutdown = false;
        volatile int activeThreads = 0;
        public int MaxThreads { get; set; } = 4;
        public bool UseShellThumbnail { get; set; } = true;

        public ThreadedThumbnailLoader()
        {
            context = SynchronizationContext.Current;
            queue = new ConcurrentQueue<ThumbnailWorkItem>();
            schedule = new ConcurrentDictionary<DataTags, ThumbnailWorkItem>();
        }

        public void ScheduleForLoad(DataTags o, Size imageSize)
        {
            var thumb = new ThumbnailWorkItem(o, imageSize);
            schedule[o] = thumb;
            queue.Enqueue(thumb);

            lock (locker)
            {
                if (((UseShellThumbnail && activeThreads < MaxThreads * 2) || activeThreads < MaxThreads) && !shutdown)
                {
                    Interlocked.Increment(ref activeThreads);
                    ThreadPool.QueueUserWorkItem(new WaitCallback(DoWork));
                }
            }
        }

        public bool HasBeenScheduled(DataTags o)
        {
            return schedule.ContainsKey(o);
        }

        public void Clear()
        {
            lock (locker)
            {
                if (activeThreads > 0)
                {
                    shutdown = true;
                }

                schedule.Clear();
                queue = new ConcurrentQueue<ThumbnailWorkItem>();
            }
        }

        private void DoWork(object obj)
        {
            while (queue.TryDequeue(out ThumbnailWorkItem result))
            {
                if (shutdown) //bail if shutting down
                    break;

                if (UseShellThumbnail)
                {
                    using (ShellFile shellFile = ShellFile.FromFilePath(result.Tag.ImagePath))
                    {
                        if (shutdown)
                            break;

                        using (var hBitmap = shellFile.Thumbnail.LargeBitmap)
                        {
                            if (shutdown)
                                break;
                            var thumbnail = BitmapResizer.ResizeBitmap(hBitmap, new BitmapResizeGDISettings(GDIResizePresent.HighSpeed, result.ImageSize) { AddPadding = true, PaddingColor = Color.Transparent });
                            if (!shutdown)
                                OnLoadedThumbnail(result.Tag, thumbnail);
                        }
                    }
                    try
                    {
 
                    }
                    catch (Exception) { }
                }
                else
                {
                    using (var img = ImageUtil.LoadBitmap(result.Tag.ImagePath))
                    {
                        if (shutdown)
                            break;

                        try
                        {
                            Bitmap thumbnail = BitmapResizer.ResizeBitmap(img, new BitmapResizeGDISettings(GDIResizePresent.HighSpeed, result.ImageSize) { AddPadding = true, PaddingColor = Color.Transparent });
                            if (!shutdown)
                                OnLoadedThumbnail(result.Tag, thumbnail);
                        }
                        catch (Exception) { }
                    }
                }
            }

            lock (locker)
            {
                if (Interlocked.Decrement(ref activeThreads) == 0)
                {
                    shutdown = false;
                }
            }
        }
    }
}
